package com.neusoft.neuiotms.dcam.ftp;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.List;

import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import com.neusoft.bizcore.auth.common.bean.UserBean;
import com.neusoft.neuiotms.common.constant.AHConstants;
import com.neusoft.neuiotms.dcam.fixed.model.Asset;
import com.neusoft.neuiotms.dcam.fixed.model.AssetType;
import com.neusoft.neuiotms.dcam.fixed.repository.AssetRepository;
import com.neusoft.neuiotms.dcam.fixed.repository.AssetTypeRepository;
import com.neusoft.neuiotms.dcam.workflow.dto.RukuFinanceAssetSLDTO;
import com.neusoft.neuiotms.dcam.workflow.dto.RukuFinanceSLDTO;
import com.neusoft.neuiotms.dcam.workflow.service.RukuFinanceSLService;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@EnableScheduling
@Service
@ConditionalOnProperty(name = "ftp.enabled", havingValue = "true")
public class SyncFinanceAsset {
    @Value("${ftp.host:''}")
    private String ftpHost;
    @Value("${ftp.port:21}")
    private int ftpPort;
    @Value("${ftp.username:''}")
    private String ftpUsername;
    @Value("${ftp.password:''}")
    private String ftpPassword;
    @Value("${ftp.basepath:''}")
    private String ftpBasepath;
    @Value("${ftp.filename:''}")
    private String filename;
    @Value("${ftp.test:false}")
    private boolean test;

    //    @Autowired
    //    private AssetConverter assetConverter;
    //
    @Autowired
    private AssetRepository assetRepository;

    @Autowired
    private AssetTypeRepository assetTypeRepository;

    @Autowired
    private RukuFinanceSLService rukuFinanceSLService;

    //    @Autowired
    //    private AuthMicroService authMicroService;

    // 每天23点执行一次
    @Scheduled(cron = "0 0 23 * * ?")
    // 每1小时执行一次
    // @Scheduled(cron = "0 0 0/1 * * ?")
    //    @Scheduled(cron = "0 0/10 * * * ?")
    public void run() {
        SyncFinanceAsset.log.info("start to syn nc asset from ftp server.");
        final Calendar now = Calendar.getInstance();
        final Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, -1);
        final String yesterday = DateFormatUtils.format(cal, "yyyyMMdd");
        InputStream inputStream = null;
        if (!this.test) {
            inputStream = this.getFtpFile(yesterday);
        } else {
            inputStream = this.getLocalFile(yesterday);
        }
        if (null == inputStream) {
            return;
        }

        try {
            final BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));

            String line = null;
            final List<RukuFinanceAssetSLDTO> preparedList = Lists.newArrayList();
            List<String> baofeiCardList = Lists.newArrayList();
            while ((line = br.readLine()) != null) {
                line = line.replace("\"", "");
                final String[] fileds = line.split(",");
                if (fileds.length != 15) {
                    SyncFinanceAsset.log.warn("line data fields are not equal 15, ignore it.");
                    continue;
                }

                final RukuFinanceAssetSLDTO syncAsset = new RukuFinanceAssetSLDTO();

                // 资产卡片
                final String assetCard = fileds[1].trim();
                if (StringUtils.isBlank(assetCard)) {
                    SyncFinanceAsset.log.warn("asset card is blank, ignore. {}", line);
                    continue;
                }
                syncAsset.setCard(assetCard);
                // 小类型编码
                final String assetSmallTypeCode = fileds[2].trim();
                final AssetType assetType = this.assetTypeRepository.findByMappingKey(assetSmallTypeCode);
                if (null == assetType) {
                    SyncFinanceAsset.log.warn("asset type mapping key {} not found.", assetSmallTypeCode);
                    continue;
                }
                syncAsset.setSmallTypeCode(assetType.getCode());
                syncAsset.setSmallTypeName(assetType.getName());
                syncAsset.setMiddleTypeCode(assetType.getParent().getCode());
                syncAsset.setMiddleTypeName(assetType.getParent().getName());
                syncAsset.setBigTypeCode(assetType.getParent().getParent().getCode());
                syncAsset.setBigTypeName(assetType.getParent().getParent().getName());

                //资产名称
                final String assetName = fileds[3].trim();
                if (StringUtils.isBlank(assetName)) {
                    SyncFinanceAsset.log.warn("asset name is blank, ignore. {}", line);
                    continue;
                }
                syncAsset.setName(assetName);

                // 购置时间
                final String assePurchaseDateStr = fileds[4].trim();
                if (StringUtils.isBlank(assePurchaseDateStr) || "00000000".equals(assePurchaseDateStr)) {
                    //syncAsset.setPurchaseDate(new Date());
                } else {
                    try {
                        final Date parsedDate = DateUtils.parseDate(assePurchaseDateStr, "yyyyMMdd");
                        syncAsset.setPurchaseDate(parsedDate);
                    } catch (final ParseException e) {
                        syncAsset.setPurchaseDate(new Date());
                    }
                }
                // 品牌名称
                final String brand = fileds[5].trim();
                syncAsset.setBrand(brand);
                // 规格型号
                final String specifications = fileds[6].trim();
                syncAsset.setSpecifications(specifications);
                // 序列号
                final String assetSerialnumber = fileds[7].trim();
                syncAsset.setSerialnumber(assetSerialnumber);
                // 计量单位
                final String assetMeasureUnit = fileds[8].trim();
                syncAsset.setMeasureUnit(assetMeasureUnit);
                // 数量
                final String assetAmount = fileds[9].trim();
                if (NumberUtils.isCreatable(assetAmount)) {
                    syncAsset.setAmount(Integer.valueOf(assetAmount));
                } else {
                    syncAsset.setAmount(1);
                }
                // 总价
                final String totalMoneyStr = fileds[10].trim();
                try {
                    syncAsset.setMoney(Double.parseDouble(totalMoneyStr));
                } catch (final Exception e) {
                    syncAsset.setMoney(0.0);
                }
                // 使用期限
                final String assetUsePeriod = fileds[11].trim();
                try {
                    final int usePeriod = Integer.valueOf(assetUsePeriod);
                    syncAsset.setUsePeriod(String.valueOf(usePeriod));
                } catch (final Exception e) {
                }
                syncAsset.setNote(yesterday + " 财管同步");

                // 使用人
                final String assetUser = fileds[13].trim();
                // 使用部门
                final String assetUserAddress = fileds[14].trim();
                syncAsset.setPurpose("使用部门：" + assetUserAddress + " 使用人：" + assetUser);

                final String baofeiDateStr = fileds[12].trim();
                if ("00000000".equals(baofeiDateStr) || StringUtils.isEmpty(baofeiDateStr)) {
                    preparedList.add(syncAsset);
                } else {
                    baofeiCardList.add(syncAsset.getCard());
                }
                baofeiCardList = new ArrayList<>(new HashSet<>(baofeiCardList));

            }

            if (baofeiCardList.size() > 0) {
                SyncFinanceAsset.log.warn("通过财管同步资产，报废的资产卡片{}", String.join(",", baofeiCardList));
                for (final String card : baofeiCardList) {
                    final List<Asset> assets =
                            this.assetRepository.findByOriginalCodeAndBelongs(card, AHConstants.BELONG_SL_CODE);
                    assets.forEach(it -> it.setStatus("toScrap"));
                    this.assetRepository.saveAll(assets);
                }
            }

            SyncFinanceAsset.log.info("will save {} assets in ftp file", preparedList.size());
            if (preparedList.size() == 0) {
                return;
            }

            final RukuFinanceSLDTO main = new RukuFinanceSLDTO();
            main.setTitle("财管系统资产同步");
            main.setReceiveDate(now.getTime());
            main.setAssetList(preparedList);

            //            final Searchable params = new Searchable();
            //            params.put("roleCode", AHConstants.ROLE_SL_ASSET_OWNER_ADMIN);
            //            final ResultListDTO<Map<String, Object>> results = this.authMicroService.allUsers(params);
            //            final List<Map<String, Object>> lists = results.getData();
            //            if (lists.size() > 0) {
            //                final UserBean user = new UserBean();
            //                user.setUsername((String) lists.get(0).get("username"));
            //                user.setName((String) lists.get(0).get("name"));
            //                this.rukuFinanceSLService.create(main, user);
            //            } else {
            //                SyncFinanceAsset.log.warn("系統未配置资产归口管理员，无法创建工单");
            //            }
            final UserBean user = new UserBean();
            user.setUsername("admin");
            user.setName("财管资产");
            this.rukuFinanceSLService.create(main, user);

        } catch (final IOException e) {
            SyncFinanceAsset.log.error("", e);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (final IOException e) {
                    SyncFinanceAsset.log.error("", e);
                }
            }

        }

    }

    private FTPClient ftpClient() {
        final FTPClient ftpClient = new FTPClient();
        ftpClient.setConnectTimeout(1000 * 30);
        ftpClient.setControlEncoding("utf-8");
        ftpClient.setDefaultPort(this.ftpPort);
        try {
            ftpClient.connect(this.ftpHost, this.ftpPort);
            ftpClient.login(this.ftpUsername, this.ftpPassword);
            final int replyCode = ftpClient.getReplyCode();
            if (!FTPReply.isPositiveCompletion(replyCode)) {
                ftpClient.disconnect();
                SyncFinanceAsset.log.error("unconnected to ftp server, username or password is invalide");
                return null;
            } else {
                SyncFinanceAsset.log.info("success to connect to ftp server.");
                return ftpClient;
            }
        } catch (final Exception e) {
            SyncFinanceAsset.log.error("", e);
        }
        return ftpClient;
    }

    private InputStream getFtpFile(String date) {
        final FTPClient ftpClient = this.ftpClient();

        if (ftpClient == null) {
            SyncFinanceAsset.log.warn("FTP client is not available.");
            return null;
        }

        InputStream inputStream = null;
        try {
            ftpClient.changeWorkingDirectory(this.ftpBasepath);
            final FTPFile[] ftpFiles = ftpClient.listFiles(this.ftpBasepath);
            boolean prepared = false;
            for (final FTPFile ftpFile : ftpFiles) {
                if ((this.filename + "_" + date + ".ok").equalsIgnoreCase(ftpFile.getName())) {
                    prepared = true;
                    break;
                }
            }
            if (!prepared) {
                SyncFinanceAsset.log.warn("asset file has not completed, wait to next hour.");
                return null;
            }

            FTPFile dataFile = null;
            for (final FTPFile ftpFile : ftpFiles) {
                if ((this.filename + ".txt").equalsIgnoreCase(ftpFile.getName())) {
                    dataFile = ftpFile;
                    break;
                }
            }

            if (null == dataFile) {
                SyncFinanceAsset.log.warn("dont't find {}.txt file.", this.filename);
                return null;
            }

            inputStream = ftpClient.retrieveFileStream(this.ftpBasepath + dataFile.getName());

            ftpClient.logout();
        } catch (final Exception e) {
            SyncFinanceAsset.log.error("", e);
        } finally {
            if (ftpClient.isConnected()) {
                try {
                    ftpClient.disconnect();
                } catch (final IOException e) {
                    SyncFinanceAsset.log.error("", e);
                }
            }
        }
        return inputStream;
    }

    private InputStream getLocalFile(String date) {
        final File file = new File("D:\\gdzc.txt");
        try {
            return new FileInputStream(file);
        } catch (final FileNotFoundException e) {
            SyncFinanceAsset.log.error("", e);
        }
        return null;
    }

}
